package com.fishbone.secure.dynamic;

import com.fishbone.common.utils.FastJsonUtil;
import com.fishbone.secure.config.FishBoneSecureProperties;
import com.fishbone.secure.entity.WhiteName;
import com.fishbone.secure.service.MetaResourceService;
import com.fishbone.secure.service.RoleService;
import com.fishbone.secure.support.CurrentUserContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 参考 ExpressionBasedFilterInvocationSecurityMetadataSource
 *
 * @author Felordcn
 * @since 14:27 2019/11/27
 **/

@Slf4j
public class DynamicFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    private static final String SUPPER_AUTH = "ROLE_ADMIN";
    @Resource
    private RequestMatcherCreator requestMatcherCreator;
    @Resource
    private MetaResourceService metaResourceService;
    @Resource
    private RoleService roleService;
    @Resource
    private FishBoneSecureProperties secureProperties;

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        log.info("当前请求的资源:{},请求的方法类型:{},请求参数:{}",request.getRequestURI(),request.getMethod(), FastJsonUtil.toJSONString(request.getParameterMap()));
        List<WhiteName> whiteNames = secureProperties.getWhiteNames();
        Set<String> whiteUris = new HashSet<>();
        if(!CollectionUtils.isEmpty(whiteNames)){
            whiteNames.forEach(whiteName -> whiteUris.add(whiteName.getUri()));
        }
        // 1. 如果是白名单地址直接放行不做动态权限的验证
        if (whiteUris.contains(request.getRequestURI())) {
            return Collections.emptyList();
        }
        // 2. 如果是超级用户直接放行不做动态权限的验证
        if(CurrentUserContextHolder.getAuthorities().contains(SUPPER_AUTH)){
            return Collections.emptyList();
        }
        Set<RequestMatcher> requestMatchers = requestMatcherCreator.convertToRequestMatcher(metaResourceService.queryPatternsAndMethods());
        // 拿到其中一个  没有就算非法访问
        RequestMatcher reqMatcher = requestMatchers.stream().filter(requestMatcher -> requestMatcher.matches(request)).findAny().orElseThrow(() -> new AccessDeniedException("非法访问"));

        AntPathRequestMatcher antPathRequestMatcher = (AntPathRequestMatcher) reqMatcher;
        // 根据pattern 获取该pattern被授权给的角色
        String pattern = antPathRequestMatcher.getPattern();
        Set<String> roles = roleService.queryRoleByPattern(pattern);

        return CollectionUtils.isEmpty(roles) ? null : SecurityConfig.createList(roles.toArray(new String[0]));
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<String> roles = roleService.queryAllAvailable();
        return CollectionUtils.isEmpty(roles) ? null : SecurityConfig.createList(roles.toArray(new String[0]));
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}
